package com.example.dense_rack_server.utils.Netty;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.dense_rack_server.Application;
import com.example.dense_rack_server.entity.*;
import com.example.dense_rack_server.mapper.*;
import com.example.dense_rack_server.service.HostService;
import com.example.dense_rack_server.utils.CabinetLoginStatus;
import com.example.dense_rack_server.utils.DateFormat;
import com.example.dense_rack_server.utils.AdrAddress;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.*;

@Slf4j
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
    //定义一个channle 组，管理所有的channel GlobalEventExecutor.INSTANCE) 是全局的事件执行器，是一个单例
    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * 有客户端与服务器发生连接时执行此方法
     * 1.打印提示信息
     * 2.将客户端保存到 channelGroup 中
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        String clientIp = Convert.toStr(channel.remoteAddress());
        System.err.println(DateFormat.getTime() + "有新的客户端与服务器发生连接。客户端地址：" + clientIp);
        channelGroup.add(channel);

        clientIp = clientIp.split(":")[0].replace("/", "");
        HostMapper hostMapper = Application.ac.getBean(HostMapper.class);
        Host host = hostMapper.selectOne(new QueryWrapper<Host>().eq("ip", clientIp));
        if (host != null) {
            host.setOnlineStatus(1);
            hostMapper.updateById(host);
        }
    }

    /**
     * 当有客户端与服务器断开连接时执行此方法，此时会自动将此客户端从 channelGroup 中移除
     * 1.打印提示信息
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        System.err.println(DateFormat.getTime() + "有客户端与服务器断开连接。客户端地址：" + ctx.channel().remoteAddress());
        String clientIp = ctx.channel().remoteAddress().toString().split(":")[0].replace("/", "");
        HostMapper hostMapper = Application.ac.getBean(HostMapper.class);
        Host host = hostMapper.selectOne(new QueryWrapper<Host>().eq("ip", clientIp));
        if (host != null) {
            host.setOnlineStatus(0);
            hostMapper.updateById(host);
        }

        channelGroup.remove(ctx.channel());

    }

    /**
     * 表示channel 处于活动状态
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println(DateFormat.getTime() + ctx.channel().remoteAddress() + " 处于活动状态");
    }

    /**
     * 表示channel 处于不活动状态
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        System.out.println(DateFormat.getTime() + ctx.channel().remoteAddress() + " 处于不活动状态");
        String clientIp = ctx.channel().remoteAddress().toString().split(":")[0].replace("/", "");
        HostMapper hostMapper = Application.ac.getBean(HostMapper.class);
        Host host = hostMapper.selectOne(new QueryWrapper<Host>().eq("ip", clientIp));
        if (host != null) {
            host.setOnlineStatus(0);
            hostMapper.updateById(host);
        }

        channelGroup.remove(ctx.channel());
    }

    /**
     * 读取到客户端发来的数据数据
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String message) throws IOException {
        //获取到当前channel
        Channel channel = ctx.channel();
        String clientIp = Convert.toStr(channel.remoteAddress());
        System.err.println(DateFormatUtils.format(System.currentTimeMillis()
                , "yyyy-MM-dd HH:mm:ss:SSS") + "有客户端发来的数据。地址：" + clientIp + " 内容：" + message);
        // 静态方法注入bean解决方案
        ArchivesMapper archivesMapper = Application.ac.getBean(ArchivesMapper.class);
        HostService hostService = Application.ac.getBean(HostService.class);
        HostTemHumMapper hostTemHumMapper = Application.ac.getBean(HostTemHumMapper.class);
        CabinetLoginStatus cabinetLoginStatus = Application.ac.getBean(CabinetLoginStatus.class);
        BorrowingRecordsMapper borrowingRecordsMapper = Application.ac.getBean(BorrowingRecordsMapper.class);
        NoticeMapper noticeMapper = Application.ac.getBean(NoticeMapper.class);
        SysParamsetMapper sysParamsetMapper = Application.ac.getBean(SysParamsetMapper.class);

        clientIp = clientIp.split(":")[0].replace("/", "");

        Host host = hostService.getOne(new QueryWrapper<Host>().like("ip", clientIp));

        JSONObject requestMap = JSONUtil.parseObj(message);
        String cmdName = requestMap.getStr("type");
        if (cmdName.equals("query") || cmdName.equals("query1")) {
            // 查询
            IPage<Map<String, Object>> archivesPage = new Page<>(requestMap.getInt("page"), requestMap.getInt("limit"));
            QueryWrapper<Archives> archivesQueryWrapper = new QueryWrapper<>();
            if (requestMap.getStr("key").equals("RFID")) {
                archivesQueryWrapper.eq("file_id", requestMap.getStr("word"));
            }
            if (requestMap.getStr("key").equals("barcode")) {

            }
            if (requestMap.getStr("key").equals("filename")) {
                archivesQueryWrapper.like("file_name", requestMap.getStr("word"));
            }
            archivesQueryWrapper.select("id as fileId", "file_name as name", "status", "file_id as rfid", "area_code", "column_number", "dense_rack_region", "joint"
                    , "layer_number", "position").eq("area_code", host.getCabinetNumber());
            archivesPage = archivesMapper.selectMapsPage(archivesPage, archivesQueryWrapper);
            List<Map<String, Object>> archivesList = archivesPage.getRecords();
            for (Map<String, Object> map : archivesList) {
                StringBuilder position = new StringBuilder();
                int areaCode = map.get("area_code").toString().length();
                if (areaCode == 1) {
                    position.append("0").append(map.get("area_code"));
                } else {
                    position.append(map.get("area_code"));
                }
                int columnNumber = map.get("column_number").toString().length();
                if (columnNumber == 1) {
                    position.append("0").append(map.get("column_number"));
                } else {
                    position.append(map.get("column_number"));
                }
                position.append(map.get("dense_rack_region"))
                        .append(map.get("joint")).append(map.get("layer_number"));
                int positionLength = map.get("position").toString().length();
                if (positionLength == 1) {
                    position.append("0").append(map.get("position"));
                } else {
                    position.append(map.get("position"));
                }
                map.put("position", position.toString());

                map.remove("area_code");
                map.remove("column_number");
                map.remove("dense_rack_region");
                map.remove("joint");
                map.remove("layer_number");
            }

            Map<String, Object> map = new HashMap<>();
            if (requestMap.getStr("type").equals("query")) {
                map.put("type", "queryResult");
            } else {
                map.put("type", "queryResult1");
            }
            map.put("dataCount", archivesPage.getTotal());
            map.put("data", archivesPage.getRecords());
            map.put("page", requestMap.getInt("page"));
            double pageCount = Math.ceil((double) archivesPage.getTotal() / requestMap.getInt("limit"));
            map.put("pageCount", Convert.toInt(pageCount));
            String sendLedMap = JSONUtil.toJsonStr(map);
            log.info("查询数据返回数据：" + sendLedMap);
            byte[] TemplatesToSendData = SendCmd.parse(sendLedMap);
            ctx.writeAndFlush(Unpooled.buffer().writeBytes(TemplatesToSendData));
            return;
        } else if (cmdName.equals("pulse")) {
            // 心跳包
            UpdateWrapper<Host> hostUpdateWrapper = new UpdateWrapper<>();
            hostUpdateWrapper.eq("id", host.getId());
            hostUpdateWrapper.set("online_status", 1);
            hostService.update(hostUpdateWrapper);
            Map<String, Object> map = new HashMap<>();
            map.put("type", requestMap.getStr("type"));
            map.put("aaaaa", "tian-aaaaa");
            String sendLedMap = JSONUtil.toJsonStr(map);
            byte[] TemplatesToSendData = SendCmd.parse(sendLedMap);
            ctx.writeAndFlush(Unpooled.buffer().writeBytes(TemplatesToSendData));
            return;
        } else if (cmdName.equals("temhum")) {
            // 温湿度
            HostTemHum hostTemHum = new HostTemHum();
            hostTemHum.setTemperature(Convert.toStr(requestMap.getInt("tem") / 10));
            hostTemHum.setHumidity(Convert.toStr(requestMap.getInt("hum") / 10));
            hostTemHum.setHostId(host.getId());
            hostTemHum.setCreateTime(DateFormat.getTime());
            hostTemHumMapper.insert(hostTemHum);
            return;
        } else if (cmdName.equals("get_time")) {
            // 同步时间
            Map<String, Object> map = new HashMap<>();
            map.put("type", "sync_time");
            map.put("time", DateUtil.currentSeconds());
            String sendLedMap = JSONUtil.toJsonStr(map);
            byte[] TemplatesToSendData = SendCmd.parse(sendLedMap);
            ctx.writeAndFlush(Unpooled.buffer().writeBytes(TemplatesToSendData));
            return;
        } else if (cmdName.equals("taskResult")) {
            // 借阅任务下发领取回调接口
            // 修改档案状态
            Archives archives = archivesMapper.selectById(requestMap.getInt("fileId"));
            if (requestMap.getStr("operation").equals("borrow") || requestMap.getStr("operation").equals("restore")) {
                UpdateWrapper<Archives> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("id", requestMap.getInt("fileId"));
                if (requestMap.getStr("operation").equals("borrow")) {
                    updateWrapper.set("status", 1);
                } else if (requestMap.getStr("operation").equals("restore")) {
                    updateWrapper.set("status", 0);
                }
                updateWrapper.set("update_time", DateFormat.getTime());
                int result = archivesMapper.update(null, updateWrapper);
                if (result > 0) {
                    if (requestMap.getInt("source") == 0) {
                        log.info("服务器下发的任务");
                        UpdateWrapper<BorrowingRecords> borrowingRecordsUpdateWrapper = new UpdateWrapper<>();
                        borrowingRecordsUpdateWrapper.eq("file_id", requestMap.getInt("fileId"));
                        if (requestMap.getStr("operation").equals("borrow")) {
                            borrowingRecordsUpdateWrapper.set("data_status", 0);
                        } else if (requestMap.getStr("operation").equals("restore")) {
                            borrowingRecordsUpdateWrapper.set("data_status", 1);
                        }
                        borrowingRecordsMapper.update(null, borrowingRecordsUpdateWrapper);

                        // 修改档案状态
                        UpdateWrapper<Archives> archivesUpdateWrapper = new UpdateWrapper<>();
                        archivesUpdateWrapper.eq("id", requestMap.getInt("fileId"));
                        if (requestMap.getStr("operation").equals("borrow")) {
                            archivesUpdateWrapper.set("status", 1);
                        } else if (requestMap.getStr("operation").equals("restore")) {
                            archivesUpdateWrapper.set("status", 0);
                        }
                        archivesMapper.update(null, archivesUpdateWrapper);
                    } else if (requestMap.getInt("source") == 1) {
                        log.info("客户端下发的任务");
                        BorrowingRecords borrowingRecords = new BorrowingRecords();
                        borrowingRecords.setFileId(archives.getId());
                        borrowingRecords.setFileName(archives.getFileName());
                        String userName = requestMap.getStr("userName");
                        borrowingRecords.setUserName(userName);
                        borrowingRecords.setCreateTime(DateFormat.getTime());
                        if (requestMap.getStr("operation").equals("borrow")) {
                            borrowingRecords.setDataStatus(0);
                            borrowingRecords.setOperation(userName + "用户柜体端借阅" + archives.getFileName() + "档案");
                        } else if (requestMap.getStr("operation").equals("restore")) {
                            borrowingRecords.setDataStatus(1);
                            borrowingRecords.setOperation(userName + "用户柜体端归还" + archives.getFileName() + "档案");
                        }
                        borrowingRecords.setStatus(1);
                        borrowingRecords.setModuleType(2);
                        borrowingRecords.setHostId(host.getId());
                        borrowingRecordsMapper.insert(borrowingRecords);
                        // 修改档案状态
                        UpdateWrapper<Archives> archivesUpdateWrapper = new UpdateWrapper<>();
                        archivesUpdateWrapper.eq("id", requestMap.getInt("fileId"));
                        if (requestMap.getStr("operation").equals("borrow")) {
                            archivesUpdateWrapper.set("status", 1);
                        } else if (requestMap.getStr("operation").equals("restore")) {
                            archivesUpdateWrapper.set("status", 0);
                        }
                        archivesMapper.update(null, archivesUpdateWrapper);
                    }
                }
                // 执行完毕关灯
                String sysType = sysParamsetMapper.selectById(2).getParamValue();
                if (sysType.equals("3")) {
                    // 表示是rfid密集架
                    rfidLightsAllOff(host);
                }

            } else if (requestMap.getStr("operation").equals("delete")) {
                // 删除档案
                int result = archivesMapper.deleteById(archives.getId());
                if (result > 0) {
                    BorrowingRecords borrowingRecords = new BorrowingRecords();
                    borrowingRecords.setFileId(archives.getId());
                    borrowingRecords.setFileName(archives.getFileName());
                    borrowingRecords.setUserName(requestMap.getStr("userName"));
                    borrowingRecords.setCreateTime(DateFormat.getTime());
                    borrowingRecords.setDataStatus(4);
                    borrowingRecords.setStatus(1);
                    borrowingRecords.setModuleType(2);
                    borrowingRecords.setOperation(requestMap.getStr("userName") + "用户柜体端删除" + archives.getFileName() + "档案");
                    borrowingRecords.setHostId(host.getId());
                    borrowingRecordsMapper.insert(borrowingRecords);
                }
            }
        } else if (cmdName.equals("serverLoginStatus")) {
            // 服务器登录状态
            cabinetLoginStatus.set("serverLoginStatus", requestMap.getStr("status"));
        } else if (cmdName.equals("getUsage")) {
            // 列详情
            QueryWrapper<Archives> archivesQueryWrapper = new QueryWrapper<Archives>().eq("area_code", host.getCabinetNumber())
                    .eq("column_number", requestMap.getInt("lie"));
            List<Archives> archivesList = archivesMapper.selectList(archivesQueryWrapper);
            int borrowCount = 0;
            int restoreCount = 0;
            for (Archives archive : archivesList) {
                if (archive.getStatus() == 1 || archive.getStatus() == 3) {
                    borrowCount++;
                } else if (archive.getStatus() == 0 || archive.getStatus() == 2) {
                    restoreCount++;
                }
            }
            Map<String, Object> map = new HashMap<>();
            map.put("type", "usage");
            map.put("region", host.getCabinetNumber());
            map.put("lie", requestMap.getInt("lie"));
            map.put("total", archivesList.size());
            map.put("borrowed", borrowCount);
            map.put("existed", restoreCount);
            String sendLedMap = JSONUtil.toJsonStr(map);
            log.info("获取柜体使用情况返回数据：" + sendLedMap);
            byte[] TemplatesToSendData = SendCmd.parse(sendLedMap);
            ctx.writeAndFlush(Unpooled.buffer().writeBytes(TemplatesToSendData));
            return;
        } else if (cmdName.equals("get_notice")) {
            //获取公告
            QueryWrapper<Notice> noticeQueryWrapper = new QueryWrapper<>();
            noticeQueryWrapper.eq("host_id", host.getId()).eq("column_number", requestMap.getInt("lie"));
            Notice notice = noticeMapper.selectOne(noticeQueryWrapper);
            if (notice != null) {
                Map<String, Object> map = new HashMap<>();
                map.put("type", "notice");
                map.put("lie", requestMap.getInt("lie"));
                map.put("notice", notice.getNoticeContent());
                String sendLedMap = JSONUtil.toJsonStr(map);
                log.info("获取公告返回数据：" + sendLedMap);
                byte[] TemplatesToSendData = SendCmd.parse(sendLedMap);
                ctx.writeAndFlush(Unpooled.buffer().writeBytes(TemplatesToSendData));
                return;
            }
        } else if (cmdName.equals("task_start")) {
            // 下发任务执行开始
            Archives archives = archivesMapper.selectById(requestMap.getInt("fileId"));
            JSONObject rfidList = JSONUtil.parseObj(host.getRfidList());
            String sendRfidIp = rfidList.get("rfidColumn" + archives.getColumnNumber()).toString();

            if (archives != null) {
                int position = archives.getPosition();
                int board = 1;
                if (position > 8) {
                    board = 2;
                    position = position - 8;
                }
                int adr = AdrAddress.calculateADR(archives.getJoint(), archives.getLayerNumber(), board, host.getColumnNumber());
                log.info("任务开始执行，地址：" + sendRfidIp + " 地址码：" + adr);
                Map<String, Object> ledMap = new LinkedHashMap<>();
                ledMap.put("adr", adr);
                ledMap.put("cd", "ledon");
                ledMap.put("pcd", position);
                log.info("下发任务执行开始发送开灯指令" + JSONUtil.toJsonStr(ledMap));
                new Client().send("\n" + JSONUtil.toJsonStr(ledMap), sendRfidIp, false);
            }
            return;

        } else if (cmdName.equals("task_cancel")) {
            // 下发任务执行取消
            rfidLightsAllOff(host);
        }

        // {"type":"alarm","msg":"电机过流：第7列"}
//        {"type":"alarm","msg":"电机霍尔信号编码错误：第7列"}
    }

    /**
     * rfid密集架全部列关灯
     *
     * @param host
     */
    public void rfidLightsAllOff(Host host) {
        JSONObject rfidList = JSONUtil.parseObj(host.getRfidList());
        for (String key : rfidList.keySet()) {
            String sendRfidIp = rfidList.get(key).toString();
            Map<String, Object> ledMap = new LinkedHashMap<>();
            ledMap.put("adr", 0);
            ledMap.put("cd", "ledclear");

            log.info(key.substring(10) + "列下发任务取消关灯" + JSONUtil.toJsonStr(ledMap));
            try {
                new Client().send("\n" + JSONUtil.toJsonStr(ledMap), sendRfidIp, false);
            } catch (Exception e) {
                log.error("下发任务取消关灯失败：" + e.getMessage());
            }
        }
    }

    /**
     * 处理异常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error(DateFormat.getTime() + "发生异常。异常信息：{}", cause.getMessage());
        //关闭通道
//        ctx.close();
    }

    /**
     * service 获取所有连接信息
     */
    public static List<String> getConnectionStatus() {
        List<String> ipList = new ArrayList<>();
        for (Channel channel : NettyServerHandler.channelGroup) {
            InetSocketAddress address = (InetSocketAddress) channel.remoteAddress();
            String ipAddress = address.getAddress().getHostAddress();
            int port = address.getPort();
            System.out.println("Remote IP: " + ipAddress + ", Port: " + port);
            ipList.add(ipAddress);
        }
        return ipList;
    }
}